package com.bright.ghj.overt.manager.impl;

import com.bright.ghj.common.util.StringUtil;
import com.bright.ghj.overt.converter.AdminMenuConverter;
import com.bright.ghj.overt.converter.NavigateConverter;
import com.bright.ghj.overt.converter.RightRoleConverter;
import com.bright.ghj.overt.converter.WebMenuConverter;
import com.bright.ghj.overt.manager.WebMenuManager;
import com.bright.ghj.overt.pojo.dto.*;
import com.bright.ghj.overt.pojo.po.primary.Navigate;
import com.bright.ghj.overt.pojo.po.primary.WebMenu;
import com.bright.ghj.overt.repository.primary.NavigateRepository;
import com.bright.ghj.overt.repository.primary.WebMenuRepository;
import com.bright.ghj.overt.pojo.po.primary.AdminMenu;
import com.bright.ghj.overt.pojo.po.primary.RightRole;
import com.bright.ghj.overt.repository.primary.AdminMenuRepository;
import com.bright.ghj.overt.repository.primary.RightRoleRepository;
import com.bright.ghj.common.util.ListUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;

@Component
@RequiredArgsConstructor
public class WebMenuManagerImpl implements WebMenuManager {

    private final WebMenuRepository webMenuRepository;
    private final AdminMenuRepository adminMenuRepository;
    private final RightRoleRepository rightRoleRepository;
    private final NavigateRepository navigateRepository;
    private final WebMenuConverter webMenuConverter;
    private final AdminMenuConverter adminMenuConverter;
    private final NavigateConverter navigateConverter;
    private final RightRoleConverter rightRoleConverter;

    @Cacheable(value = "WebMenu", key = "#root.methodName")
    @Override
    public List<WebMenuDTO> listWebMenuByCache() {
        List<WebMenu> webMenuList = webMenuRepository.findWebMenu();
        return webMenuConverter.poConvertDTO(webMenuList);
    }

    @Override
    @Cacheable(value = "AdminMenu", key = "#root.methodName + '_' + #user.username")
    public List<AdminMenuDTO> listAdminMenuByCache(UserDTO user) {

        // 获取有权限的导航
        List<RightRole> rightRoles = rightRoleRepository.findAllByPMain(user.getCwgkPmain());
        List<String> allowMenuIdList = ListUtil.toSingleList(rightRoles, RightRole::getPno);

        // TODO 当兼容多地区后 这里要按逗号分隔再判断？如果多个地区是不同级别？
        int userType = StringUtil.length(user.getDistNo()) / 2;

        List<AdminMenu> adminMenuList = adminMenuRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> ps = new ArrayList<>();
            ps.add(root.get("menuId").in(allowMenuIdList));
            // 找父级和子级导航 menuId长度为2和4的一起返回
            ps.add(criteriaBuilder.or(criteriaBuilder.equal(criteriaBuilder.length(root.get("menuId")), 2),
                    criteriaBuilder.equal(criteriaBuilder.length(root.get("menuId")), 4)));
            ps.add(criteriaBuilder.equal(root.get("isShow"), 1));
            ps.add(criteriaBuilder.greaterThanOrEqualTo(root.get("userType"), userType));

            if (user.getIsTdyh() != null && user.getIsTdyh()) {
                ps.add(criteriaBuilder.isTrue(root.get("isTsyh")));
            }

            criteriaQuery.where(ps.toArray(new Predicate[0]));
            criteriaQuery.orderBy(criteriaBuilder.asc(root.get("menuId")));
            return criteriaQuery.getRestriction();
        });

        // 将子菜单打包到父级菜单中
        List<AdminMenuDTO> result = new ArrayList<>();
        List<AdminMenu> parentMenus = ListUtil.toListByFilter(adminMenuList, adminMenu -> StringUtil.length(adminMenu.getMenuId()) == 2);
        for (AdminMenu parentMenu : parentMenus) {
            AdminMenuDTO adminMenuDTO = adminMenuConverter.poConvertDTO(parentMenu);
            // 获取子菜单
            String menuId = parentMenu.getMenuId();
            List<AdminMenuDTO> subMenus = new ArrayList<>();

            for (AdminMenu subMenu : ListUtil.toListByFilter(adminMenuList, adminMenu -> StringUtil.startsWith(adminMenu.getMenuId(), menuId) && StringUtil.length(adminMenu.getMenuId()) == 4)) {
                subMenus.add(adminMenuConverter.poConvertDTO(subMenu));
            }

            adminMenuDTO.setSubAdminMenuList(subMenus);
            result.add(adminMenuDTO);
        }
        return result;
    }

    @Override
    @Cacheable(value = "Navigate", key = "#root.methodName + '_' + #user.username")
    public List<NavigateDTO> listNavigatesByCache(UserDTO user) {
        // 获取有权限的导航
        List<RightRole> rightRoles = rightRoleRepository.findAllByPMain(user.getCwgkPmain());
        List<String> allowMenuIdList = ListUtil.toSingleList(rightRoles, RightRole::getPno);

        // 兼容多地区
        int userType;// = StringUtil.length(user.getDistNo()) / 2;
        if (user.getDistNoList() != null && user.getDistNoList().length > 0) {
            // 多地区情况下 获取最大级别（地区编号长度最小）
            userType = 100;
            for (String userDistNo : user.getDistNoList()) {
                userType = Math.min(userType, StringUtil.length(userDistNo) / 2);
            }
        } else {
            userType = StringUtil.length(user.getDistNo()) / 2;
        }
        final int userTypeFinal = userType;

        List<Navigate> navigateList = navigateRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> ps = new ArrayList<>();
            ps.add(root.get("navNo").in(allowMenuIdList));
            // 找父级和子级导航 menuId长度为2和4的一起返回
            ps.add(criteriaBuilder.or(criteriaBuilder.equal(criteriaBuilder.length(root.get("navNo")), 2),
                    criteriaBuilder.equal(criteriaBuilder.length(root.get("navNo")), 4)));
            ps.add(criteriaBuilder.equal(root.get("visible"), 1));
            ps.add(criteriaBuilder.greaterThanOrEqualTo(root.get("usertype"), userTypeFinal));

            // 这一个条件是抄旧项目的 原理未明
            if (user.getIsTdyh() != null && user.getIsTdyh()) {
                ps.add(criteriaBuilder.isTrue(root.get("isTsyh")));
            }

            criteriaQuery.where(ps.toArray(new Predicate[0]));
            criteriaQuery.orderBy(criteriaBuilder.asc(root.get("disId")));
            return criteriaQuery.getRestriction();
        });

        // 将子菜单打包到父级菜单中
        List<NavigateDTO> result = new ArrayList<>();
        List<Navigate> parentMenus = ListUtil.toListByFilter(navigateList, navigate -> StringUtil.length(navigate.getNavNo()) == 2);
        for (Navigate parentMenu : parentMenus) {
            NavigateDTO navigateDTO = getNavigateDTO(parentMenu);

            // 获取子菜单
            String navNo = parentMenu.getNavNo();
            List<NavigateDTO> subNavigates = new ArrayList<>();

            for (Navigate subNavigate : ListUtil.toListByFilter(navigateList, navigate -> StringUtil.startsWith(navigate.getNavNo(), navNo) && StringUtil.length(navigate.getNavNo()) == 4)) {
                NavigateDTO subNavigateDTO = getNavigateDTO(subNavigate);
                subNavigates.add(subNavigateDTO);
            }

            navigateDTO.setSubNavigateList(subNavigates);
            result.add(navigateDTO);
        }
        return result;
    }

    private NavigateDTO getNavigateDTO(Navigate subNavigate) {
        // 处理跳转iframe页面的情况 如果navUrl配了/frame 那么target就是iframe地址 代码处理成用frameUrl返回 target写死成前端需要的值
        String subFrameUrl = null;
        if (StringUtils.equalsIgnoreCase(subNavigate.getNavUrl(), "/frame")) {
            subFrameUrl = subNavigate.getTarget();
            subNavigate.setTarget("cwgk/common/frame");
        }
        NavigateDTO subNavigateDTO = navigateConverter.poConvertDTO(subNavigate);
        if (subFrameUrl != null) {
            subNavigateDTO.setFrameUrl(subFrameUrl);
        }
        return subNavigateDTO;
    }

    @Override
    public List<RightRoleDTO> listRightRolesByCache(UserDTO user) {
        List<RightRole> rightRoles = rightRoleRepository.findAllByPMain(user.getCwgkPmain());
        return rightRoleConverter.poConvertDTO(rightRoles);
    }


}
